#!/usr/bin/python
import os, re
import sys, time
import local_dnsperf
import perf_decorater
import gen_server_conf
import remote_op_server
from perfssh import PerfSSH
from optparse import OptionParser
from perfconfig import PerfConfig
from gen_server_conf import QUERY_FILE
from perf_decorater import time_decorater
from remote_op_server import OPBIND, OPMAPLE
from datetime import datetime
from threading import Thread

cpu = 1

PERFORMANCE_SCRIPT = 'performance_test.tgz'
CWD = os.getcwd()

def get_ssh_client_from_cf(cf):
    server = cf.get('ssh', 'server')
    port = cf.getint('ssh', 'port')
    username = cf.get('ssh', 'username')
    password = cf.get('ssh', 'password')
    timeout = cf.getint('ssh', 'timeout')

    ssh_client = PerfSSH(server, port, username, password, timeout)

    return ssh_client

def dict_to_str(dic):
    string = ''
    for key, value in dic.items():    
        if key == 'qp_file':
            continue
        string += key
        string += ':'
        string += str(value)
        string += ' '
    return string
        
@time_decorater
def main_dispatch(cf, test_list, instance_list, is_regererate=False):

    ssh_client = get_ssh_client_from_cf(cf)

    global cpus
    cpus  = ssh_client.get_server_cpus()
    outputdir = os.path.join(CWD, 'output')

    try:
        for tester in test_list:
            logfp = open(os.path.join(outputdir, tester + '_result.txt'), 'a')
            tester = tester.lower()
            server = cf.get(tester, 'server')
            port = cf.getint(tester, 'port')
            remotepath = cf.get(tester, 'remotepath')
            bg_port = cf.get(tester, 'bg_port').split(',')
            os.system("mkdir -p %s" % remotepath)
            os.system("\cp %s/%s %s" % (CWD, PERFORMANCE_SCRIPT, remotepath))

            remote_server = getattr(remote_op_server,'OP' + tester.upper())(ssh_client, server, port, bg_port, remotepath)
            conf_client = getattr(gen_server_conf, tester.capitalize() + '_conf')(server, port, remotepath)

            for instance in instance_list:
                filename = tester + '.' + instance + '.tgz'
                conf_paras = cf.items(instance)
                viewnum_list = [0]
                if 'viewnum' in conf_paras:
                    viewnum_list = [int(elem) for elem in conf_paras['viewnum'].split(',')]
                domainnum_list = [int(elem) for elem in conf_paras['domainnum'].split(',')]
                zonenum_list = [int(elem) for elem in conf_paras['zonenum'].split(',')]
                all_cases = []
                for domainnum in domainnum_list:
                    for zonenum in zonenum_list:
                        for viewnum in viewnum_list:
                            paras = conf_paras.copy()
                            paras['viewnum'] = viewnum
                            paras['zonenum'] = zonenum
                            paras['domainnum'] = domainnum 
                            if 'service' in paras:
                                for serv in paras['service'].split(','):
                                    paras['service'] = serv
                            all_cases.append(paras)

                print >>logfp, '###tester:%s instance:%s starttime:%s' % (tester, instance, datetime.now().strftime("%Y%m%d-%H%M%S"))
                for input_paras in all_cases:
                    print '***%s:%s %s' % (tester, instance, dict_to_str(input_paras))
                    print >>logfp, '***tester:%s instance:%s %s' % (tester, instance, dict_to_str(input_paras))
                    print '%s:%s:generating the confige file, plase waiting .....' % (tester, instance)
                    input_paras['qp_file'] = os.path.join(remotepath, tester + '.' + instance + '.' + QUERY_FILE)
                    if not os.path.exists(input_paras['qp_file']) or is_regererate != False:
                        print '%s:%s:generate configuration file again' % (tester, instance)
                        os.system("rm -f " + input_paras['qp_file'])
                        conf_client.remove_old_data(filename)
                        conf_client.gen_conf(input_paras)
                        conf_client.tar_file(filename)

                    remote_server.delete_file()
                    remote_server.upload_file(filename)
                    remote_server.upload_file(PERFORMANCE_SCRIPT)
                    run_server_for_test(cf, tester, instance, remote_server, input_paras, logfp)

                print >>logfp, '!!!tester:%s instance:%s endtime:%s' % (tester, instance, datetime.now().strftime("%Y%m%d-%H%M%S"))
                print >>logfp, '**' * 50 + '\n'
            logfp.close()
    except AttributeError as ept:
        print 'Exception:' + str(ept)
        sys.exit(1)
    except KeyboardInterrupt, e:
        print 'notice:interrupt by keyboard'
    finally:
        ssh_client.close()

def run_server_for_test(cf, tester, instance, remote_server, paras, fp):

    minq = cf.getint('dnsperf', 'minq')
    maxq = cf.getint('dnsperf', 'maxq')
    step = cf.getint('dnsperf', 'step')
    long = cf.getint('dnsperf', 'long')

    threadnum_list = cf.get(tester, 'threadnum')
    checktime = cf.getint(tester, 'checktime')
    remotepath = cf.get(tester, 'remotepath')
    server = cf.get(tester, 'server')
    port = cf.getint(tester, 'port')

    numlist = local_dnsperf.thread_num_list(cpus, threadnum_list)

    for threadnum in numlist:
        try:
            remote_server.before_start_server(**paras)
            remote_server.start_server(threadnum,  **paras)

            assert remote_server.check_server(checktime) == True, "start server failed\n"

            for q in range(minq, maxq + 1, step):
                remote_server.start_performance_stat()
                argkw = {'maxq':q, 'long':long}
                if instance == 'kexin_test':argkw['tsig'] = 'key1:JybkdnSoWYpoHLeF423QPQ=='
                print '%s:%s:threadnum-%d:maxq-%d' % (tester, instance, threadnum, q)
                stat= local_dnsperf.start_dnsperf(os.path.join(remotepath, tester+'.'+instance+'.'+QUERY_FILE), server, port, **argkw) 

                print >>fp, '--'*50
                print >>fp, '%s thread-num:%d maxq:%d' % (dict_to_str(stat), threadnum, q)
                print >>fp, '--'*50
                print '%s:%s %s' % (tester, instance, dict_to_str(stat))
                print '--'*50 

                remote_server.stop_performance_stat()
                perf_data = remote_server.print_performance_data("dnsperf_stat.perf")
                for elem in perf_data:print >>fp, "dynamic:" + elem,

        except KeyboardInterrupt, e:
            remote_server.stop_performance_stat()
            raise KeyboardInterrupt(e)
        finally:
            remote_server.kill_server()
            print >>fp, '==' * 50
            print '==' * 50 
    perf_data = remote_server.print_performance_data("dnsperf_stat.static")
    for elem in perf_data:print >>fp, "dynamic:" + elem,
    print >>fp, '==' * 50 
    print '**' * 50

def getopt():
    parser = OptionParser()
    parser.add_option('-c', '--conf', dest='conf', default='conf/perf.json')
    parser.add_option('-t', '--test', dest='tester', default=None)
    parser.add_option('-i', '--instance', dest='instance', default=None)
    parser.add_option('-r', '--regenerate', dest='regenerate', default=True)

    opts, args = parser.parse_args()
    if opts.conf == None:
        parser.print_help()
        sys.exit(1)

    return opts

def main(opts):
    cf = PerfConfig(opts['conf']) 

    all_test_list = cf.get_tester()
    if opts['tester'] != None:
        test_list = opts['tester'].split(',')
        for tester in test_list:
            if tester not in all_test_list:
                 print "%s tester is not exists" % tester
                 sys.exit(0)
    else:
        test_list = all_test_list

    all_instance_list = cf.get_instance()
    if opts['instance'] != None:
        instance_list = opts['instance'].split(',')
        for instance in instance_list:
            if instance not in all_instance_list:
                print "%s instance is not exists" % instance 
                sys.exit(0)
    else:
        instance_list = all_instance_list
    with open('output/' + 'usetime.log', 'w') as timelog: 
        perf_decorater.flog = timelog
        main_dispatch(cf, test_list, instance_list, opts['regenerate'])
     
if __name__ == '__main__':
    opts = getopt()
    main(vars(opts))
